package com.common.service.evaluate.impl;

import com.common.base.DictionaryAware;
import com.common.converter.CheckEvaluateConverter;
import com.common.entity.department.QDepartmentEntity;
import com.common.entity.evaluate.CheckEvaluateEntity;
import com.common.entity.evaluate.QCheckEvaluateEntity;
import com.common.entity.personal.PersonalEntity;
import com.common.entity.personal.QPersonalEntity;
import com.common.entity.target.TargetItemAssignEntity;
import com.common.excel.BaseImportVo;
import com.common.excel.ExcelListener;
import com.common.excel.ExcelUtil;
import com.common.excel.ExcelValueCheckResp;
import com.common.excel.excelinfo.CheckEvaluateExcelInfo;
import com.common.excel.excelinfo.EvaluateExportExcelInfo;
import com.common.excel.listener.CheckEvaluateExcelListener;
import com.common.global.BizException;
import com.common.global.BizServiceEnum;
import com.common.global.CommonEnum;
import com.common.query.QueryConditionVo;
import com.common.repository.evaluate.CheckEvaluateRepository;
import com.common.repository.judicialpersonal.PersonalRepository;
import com.common.requestvo.evaluate.CheckEvaluateImportReqVo;
import com.common.requestvo.evaluate.CheckEvaluateReqVo;
import com.common.requestvo.evaluate.EvaluateInitReqVo;
import com.common.service.departmentjob.DepartmentService;
import com.common.service.evaluate.CheckEvaluateService;
import com.common.vo.departmentjob.DepartmentVo;
import com.common.vo.evaluate.CheckEvaluateVo;
import com.querydsl.core.QueryResults;
import com.querydsl.core.Tuple;
import com.querydsl.jpa.impl.JPAQuery;
import com.querydsl.jpa.impl.JPAQueryFactory;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import javax.transaction.Transactional;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author johnny
 * @create 2021-05-16 3:09 下午
 **/
@Service
@Slf4j
@Transactional(rollbackOn = Exception.class)
public class CheckEvaluateServiceImpl implements CheckEvaluateService {

    private final JPAQueryFactory queryFactory;

    private final CheckEvaluateRepository checkEvaluateRepository;

    private final CheckEvaluateExcelListener checkEvaluateExcelListener;

    private final PersonalRepository personalRepository;

    private final DepartmentService departmentService;


    private final ThreadPoolTaskExecutor executor;

    public CheckEvaluateServiceImpl(JPAQueryFactory queryFactory, CheckEvaluateRepository checkEvaluateRepository, CheckEvaluateExcelListener checkEvaluateExcelListener, PersonalRepository personalRepository, PersonalRepository personalRepository1, DepartmentService departmentService, ThreadPoolTaskExecutor executor) {
        this.queryFactory = queryFactory;
        this.checkEvaluateRepository = checkEvaluateRepository;
        this.checkEvaluateExcelListener = checkEvaluateExcelListener;
        this.personalRepository = personalRepository1;
        this.departmentService = departmentService;
        this.executor = executor;
    }

    @Override
    public Page<CheckEvaluateVo> listByCondition(CheckEvaluateReqVo checkEvaluateReqVo, Pageable pageable) {

        List<CheckEvaluateVo> list = new ArrayList<>();
        QCheckEvaluateEntity qCheckEvaluateEntity = QCheckEvaluateEntity.checkEvaluateEntity;
        QDepartmentEntity qDepartmentEntity = QDepartmentEntity.departmentEntity;
        JPAQuery<Tuple> jpaQuery = queryFactory.select(qCheckEvaluateEntity, qDepartmentEntity.departmentName)
                .from(qCheckEvaluateEntity)
                .leftJoin(qDepartmentEntity).on(qDepartmentEntity.id.eq(qCheckEvaluateEntity.departmentId))
                .offset(pageable.getPageNumber() * pageable.getPageSize())
                .limit(pageable.getPageSize());

        fillCondition(jpaQuery, checkEvaluateReqVo);
        QueryResults<Tuple> queryResults = jpaQuery.fetchResults();
        queryResults.getResults().forEach(tuple -> {
            CheckEvaluateEntity checkEvaluateEntity = tuple.get(0, CheckEvaluateEntity.class);
            String departmentName = tuple.get(1, String.class);
            CheckEvaluateVo checkEvaluateVo = CheckEvaluateConverter.INSTANCE.domain2vo(checkEvaluateEntity);
            checkEvaluateVo.setDepartmentName(departmentName);
            list.add(checkEvaluateVo);
        });
        return new PageImpl<>(list, pageable, queryResults.getTotal());
    }

    @Override
    public void add(CheckEvaluateReqVo checkEvaluateReqVo) {
        checkEvaluateReqVo.setId(null);
        CheckEvaluateEntity checkEvaluateEntity = fillScoreAndPersonalRel(checkEvaluateReqVo);
        checkEvaluateRepository.save(checkEvaluateEntity);

        PersonalEntity personalEntity = personalRepository.findById(checkEvaluateReqVo.getPersonalId()).orElse(null);
        if (personalEntity != null) {
            personalEntity.setCheckEvaluateId(checkEvaluateEntity.getId());
            personalRepository.save(personalEntity);
        }

    }

    private CheckEvaluateEntity fillScoreAndPersonalRel(CheckEvaluateReqVo checkEvaluateReqVo) {
        CheckEvaluateEntity checkEvaluateEntity = CheckEvaluateConverter.INSTANCE.vo2domain(checkEvaluateReqVo);
        checkEvaluateEntity.setCheckRankScore(DictionaryAware.CHECK_RANK_MAP.get(checkEvaluateEntity.getCheckRank()));
        checkEvaluateEntity.setCheckOrderScore(DictionaryAware.CHECK_ORDER_MAP.get(checkEvaluateEntity.getCheckOrder()));
        checkEvaluateEntity.setCheckCivilScore(DictionaryAware.CHECK_CIVIL_MAP.get(checkEvaluateEntity.getCheckCivil()));
        PersonalEntity personalEntity = personalRepository.findById(checkEvaluateEntity.getPersonalId()).orElse(null);
        if (personalEntity != null) {
            checkEvaluateEntity.setPersonalName(personalEntity.getName());
        } else {
            throw new BizException(BizServiceEnum.FIND_NOT_PERSONAL_INFO);
        }
        return checkEvaluateEntity;
    }

    @Override
    public void edit(CheckEvaluateReqVo checkEvaluateReqVo) {
        if (checkEvaluateReqVo.getId() != null && checkEvaluateReqVo.getId() != 0L) {
            if (checkEvaluateRepository.existsById(checkEvaluateReqVo.getId())) {
                CheckEvaluateEntity checkEvaluateEntity = fillScoreAndPersonalRel(checkEvaluateReqVo);
                checkEvaluateRepository.save(checkEvaluateEntity);
            } else {
                throw new BizException(CommonEnum.ID_NOT_FIND_ENTITY);
            }
        } else {
            throw new BizException(CommonEnum.ID_NOT_NULL);
        }
    }

    @Override
    public void delete(Long id) {
        if (checkEvaluateRepository.existsById(id)) {
            PersonalEntity personalEntity = personalRepository.findByCheckEvaluateId(id);
            personalEntity.setCheckEvaluateId(null);
            personalRepository.save(personalEntity);
            checkEvaluateRepository.deleteById(id);
        } else {
            throw new BizException(CommonEnum.ID_NOT_FIND_ENTITY);
        }
    }

    @Override
    public void initEvaluateData(EvaluateInitReqVo evaluateInitReqVo) {
        if (evaluateInitReqVo.getYear() != null && evaluateInitReqVo.getYear() != 0L
                && evaluateInitReqVo.getMonth() != null && evaluateInitReqVo.getMonth() != 0L) {
            List<CheckEvaluateEntity> checkEvaluateEntities = new ArrayList<>();
            Long departmentId = evaluateInitReqVo.getDepartmentId();
            if (departmentId != null && departmentId != 0L) {
                DepartmentVo departmentVo = departmentService.checkDepartmentExist(departmentId);
                initEvaluateDataByDepartment(evaluateInitReqVo, departmentVo, checkEvaluateEntities);
            } else {
                List<DepartmentVo> departmentVos = departmentService.findAllDepartment();
                departmentVos.forEach(departmentVo -> initEvaluateDataByDepartment(evaluateInitReqVo, departmentVo, checkEvaluateEntities));
            }

            List<Long> personalIdList = checkEvaluateEntities.stream().map(CheckEvaluateEntity::getPersonalId).collect(Collectors.toList());
            if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(personalIdList)) {
                List<CheckEvaluateEntity> existAssignData = checkEvaluateRepository.findByPersonalIdInAndYearAndMonth(personalIdList, evaluateInitReqVo.getYear()
                        , evaluateInitReqVo.getMonth());
                List<Long> existPersonalIdList = existAssignData.stream().map(CheckEvaluateEntity::getPersonalId).collect(Collectors.toList());
                //找到 未分配的 personalIdList
                Collection<Long> noExistAssignPersonalIdList = org.apache.commons.collections4.CollectionUtils
                        .subtract(personalIdList, existPersonalIdList);
                if (CollectionUtils.isNotEmpty(noExistAssignPersonalIdList)) {
                    List<CheckEvaluateEntity> checkEvaluateDataList = checkEvaluateEntities.stream()
                            .filter(checkEvaluateEntity ->
                                    noExistAssignPersonalIdList.contains(checkEvaluateEntity.getPersonalId())).collect(Collectors.toList());
                    //初始化 数据
                    checkEvaluateRepository.saveAll(checkEvaluateDataList);
                    //把persona 个人档案中的 checkValuateId 绑定最新的 for 司法人员管理查询
                    executor.execute(() -> {
                        List<PersonalEntity> personalEntities = new ArrayList<>();
                        checkEvaluateDataList.forEach(checkEvaluateEntity -> {
                            PersonalEntity personalEntity = personalRepository.findById(checkEvaluateEntity.getPersonalId())
                                    .orElse(null);
                            if (personalEntity != null) {
                                personalEntity.setCheckEvaluateId(checkEvaluateEntity.getId());
                                personalEntities.add(personalEntity);
                            }
                        });
                        if (CollectionUtils.isNotEmpty(personalEntities)) {
                            personalRepository.saveAll(personalEntities);
                        }
                    });
                }
            }
        } else {
            throw new BizException(CommonEnum.PARAMS_SHORTAGE);
        }
    }

    @Override
    public List<EvaluateExportExcelInfo> findForExcel(CheckEvaluateReqVo checkEvaluateReqVo) {

        List<EvaluateExportExcelInfo> list = new ArrayList<>();
        QCheckEvaluateEntity qCheckEvaluateEntity = QCheckEvaluateEntity.checkEvaluateEntity;
        QDepartmentEntity qDepartmentEntity = QDepartmentEntity.departmentEntity;
        JPAQuery<Tuple> jpaQuery = queryFactory.select(qCheckEvaluateEntity, qDepartmentEntity.departmentName)
                .from(qCheckEvaluateEntity)
                .leftJoin(qDepartmentEntity).on(qDepartmentEntity.id.eq(qCheckEvaluateEntity.departmentId));

        fillCondition(jpaQuery, checkEvaluateReqVo);

        QueryResults<Tuple> queryResults = jpaQuery.fetchResults();
        queryResults.getResults().forEach(tuple -> {
            CheckEvaluateEntity checkEvaluateEntity = tuple.get(0, CheckEvaluateEntity.class);
            String departmentName = tuple.get(1, String.class);

            EvaluateExportExcelInfo evaluateExportExcelInfo = CheckEvaluateConverter.INSTANCE.domain2excelvo(checkEvaluateEntity);
            evaluateExportExcelInfo.setDepartmentName(departmentName);
            list.add(evaluateExportExcelInfo);
        });
        return list;
    }

    private void initEvaluateDataByDepartment(EvaluateInitReqVo evaluateInitReqVo, DepartmentVo departmentVo, List<CheckEvaluateEntity> checkEvaluateEntities) {

        if (departmentVo.getId() != null && departmentVo.getId() != 0L
                && StringUtils.isNotEmpty(departmentVo.getDepartmentName())) {
            //初始化 指定部门的 数据
            QPersonalEntity qPersonalEntity = QPersonalEntity.personalEntity;
            List<Tuple> fetch = queryFactory.select(qPersonalEntity.id, qPersonalEntity.name)
                    .from(qPersonalEntity)
                    .where(qPersonalEntity.departmentId.eq(departmentVo.getId()))
                    .fetch();
            fetch.forEach(tuple -> {
                CheckEvaluateEntity checkEvaluateEntity = new CheckEvaluateEntity();
                checkEvaluateEntity.setPersonalId(tuple.get(0, Long.class));
                checkEvaluateEntity.setPersonalName(tuple.get(1, String.class));
                checkEvaluateEntity.setYear(evaluateInitReqVo.getYear());
                checkEvaluateEntity.setMonth(evaluateInitReqVo.getMonth());
                checkEvaluateEntity.setDepartmentId(departmentVo.getId());
                checkEvaluateEntity.setCreateBy(evaluateInitReqVo.getCreateBy());
                checkEvaluateEntities.add(checkEvaluateEntity);
            });
        }
    }

    @Override
    public ExcelValueCheckResp importFile(BaseImportVo baseImportVo) {
        CheckEvaluateImportReqVo checkEvaluateImportReqVo = (CheckEvaluateImportReqVo) baseImportVo;
        if (checkEvaluateImportReqVo.getYear() == 0 || checkEvaluateImportReqVo.getMonth() == 0 ||
                checkEvaluateImportReqVo.getFile() == null) {
            throw new BizException(CommonEnum.PARAMS_SHORTAGE);
        }
        log.info("【start import checkEvaluate】");
        List<CheckEvaluateEntity> list = new ArrayList<>();
        log.info("【开始读取 版权片单 Excel sheet】");
        ExcelUtil.readExcel(baseImportVo.getFile(), new CheckEvaluateExcelInfo(), 1,
                checkEvaluateExcelListener);
        List<Object> dataList = ExcelListener.getDatas();
        if (ExcelListener.excelValueCheckResp().getErrorInfoRespMap().size() == 0) {
            List<Long> personalIdList = dataList.stream().map(object -> (CheckEvaluateExcelInfo) object).collect(Collectors.toList())
                    .stream().map(CheckEvaluateExcelInfo::getPersonalId).collect(Collectors.toList());

            QCheckEvaluateEntity qCheckEvaluateEntity = QCheckEvaluateEntity.checkEvaluateEntity;
            List<Long> existCheckEvaluateIdList = queryFactory.select(qCheckEvaluateEntity.id)
                    .from(qCheckEvaluateEntity)
                    .where(qCheckEvaluateEntity.personalId.in(personalIdList)
                            .and(qCheckEvaluateEntity.year.eq(checkEvaluateImportReqVo.getYear()))
                            .and(qCheckEvaluateEntity.month.eq(checkEvaluateImportReqVo.getMonth())))
                    .fetch();
            //删除 当前年份月份 每个人的 老的 评价   //删除 老的导入 当年月person的
            if (CollectionUtils.isNotEmpty(existCheckEvaluateIdList)) {
                queryFactory.delete(qCheckEvaluateEntity)
                        .where(qCheckEvaluateEntity.id.in(existCheckEvaluateIdList))
                        .execute();
            }
            dataList.forEach(checkEvaluateExcelInfo -> {
                CheckEvaluateEntity checkEvaluateEntity = CheckEvaluateConverter.INSTANCE.excelInfo2domain((CheckEvaluateExcelInfo) checkEvaluateExcelInfo);
                checkEvaluateEntity.setMonth(checkEvaluateImportReqVo.getMonth());
                checkEvaluateEntity.setYear(checkEvaluateImportReqVo.getYear());
                checkEvaluateEntity.setCreateBy(baseImportVo.getCreateBy());
                list.add(checkEvaluateEntity);
            });
            checkEvaluateRepository.saveAll(list);
            executor.execute(() -> {
                List<PersonalEntity> personalEntityList = new ArrayList<>();
                Map<Long, Long> maps = list.stream().collect(Collectors.toMap(CheckEvaluateEntity::getPersonalId, CheckEvaluateEntity::getId));
                dataList.forEach(info -> {
                    CheckEvaluateExcelInfo checkEvaluateExcelInfo = (CheckEvaluateExcelInfo) info;
                    PersonalEntity personalEntity = checkEvaluateExcelInfo.getPersonalEntity();
                    personalEntity.setCheckEvaluateId(maps.get(personalEntity.getId()));
                    personalEntityList.add(personalEntity);
                });
                personalRepository.saveAll(personalEntityList);
            });
        }

        log.info("【end import checkEvaluate】");

        return ExcelListener.excelValueCheckResp();
    }

    @Override
    public void fillCondition(JPAQuery<Tuple> jpaQuery, QueryConditionVo queryConditionVo) {
        CheckEvaluateReqVo checkEvaluateReqVo = (CheckEvaluateReqVo) queryConditionVo;
        QCheckEvaluateEntity qCheckEvaluateEntity = QCheckEvaluateEntity.checkEvaluateEntity;
        if (checkEvaluateReqVo.getYear() != null && checkEvaluateReqVo.getYear() != 0) {
            jpaQuery.where(qCheckEvaluateEntity.year.eq(checkEvaluateReqVo.getYear()));
        }
        if (checkEvaluateReqVo.getMonth() != null && checkEvaluateReqVo.getMonth() != 0) {
            jpaQuery.where(qCheckEvaluateEntity.month.eq(checkEvaluateReqVo.getMonth()));
        }
        if (checkEvaluateReqVo.getDepartmentId() != null && checkEvaluateReqVo.getDepartmentId() != 0) {
            jpaQuery.where(qCheckEvaluateEntity.departmentId.eq(checkEvaluateReqVo.getDepartmentId()));
        }
        if (checkEvaluateReqVo.getPersonalId() != null && checkEvaluateReqVo.getPersonalId() != 0) {
            jpaQuery.where(qCheckEvaluateEntity.personalId.eq(checkEvaluateReqVo.getPersonalId()));
        }
        if (StringUtils.isNotEmpty(checkEvaluateReqVo.getCheckRank())) {
            jpaQuery.where(qCheckEvaluateEntity.checkRank.eq(checkEvaluateReqVo.getCheckRank()));
        }
        if (StringUtils.isNotEmpty(checkEvaluateReqVo.getCheckOrder())) {
            jpaQuery.where(qCheckEvaluateEntity.checkOrder.eq(checkEvaluateReqVo.getCheckOrder()));
        }
        if (StringUtils.isNotEmpty(checkEvaluateReqVo.getCheckCivil())) {
            jpaQuery.where(qCheckEvaluateEntity.checkCivil.eq(checkEvaluateReqVo.getCheckCivil()));
        }
    }
}